#ifndef xpack_interface_multiptr
#define xpack_interface_multiptr
#pragma push_macro("xuser")
#undef  xuser
#define xuser mixc::interface_multiptr::inc
#include"adapter/random_access.hpp"
#include"interface/seqptr.hpp"
#include"meta/is_number.hpp"
#pragma pop_macro("xuser")

namespace mixc::interface_multiptr{
    template<class item_type, uxx rank_v>
    struct multiptr;

    template<class item_type>
    xstruct(
        xspec(multiptr, item_type, 0),
        xprif(m_ptr, item_type *)
    )
    public:
        using item_t            = item_type;
        using final_t           = the_t;
        using self_t            = item_t &;

        template<class, uxx>
        friend struct multiptr;

        constexpr multiptr() : 
            m_ptr(nullptr){}

        constexpr multiptr(the_t const &) = default;

        multiptr(item_t const * ptr, uxx const *) :
            m_ptr{ (item_t *)ptr }{
        }

        self_t self() const {
            return *m_ptr;
        }
    $

    template<class item_type, uxx rank_v>
    xstruct(
        xtmpl(multiptr, item_type, rank_v),
        xpubb(inc::random_access<multiptr<item_type, rank_v>, typename multiptr<item_type, rank_v - 1>::self_t>),
        xprif(m_ptr, item_type *),
        xprif(m_rank, uxx[rank_v])
    )
    public:
        using item_t            = item_type;
        using final_t           = the_t;
        using self_t            = the_t;

        template<class, uxx>
        friend struct multiptr;

        friend inc::random_access<the_t, typename multiptr<item_type, rank_v - 1>::self_t>;
    public:
        xprops()
            xpubgetx(length, uxx){
                xr{ return xthe.m_rank[0]; }
            };
        $

        xprops_operator()

    public:
        constexpr multiptr() : 
            m_ptr(nullptr), m_rank{}{}

        template<inc::is_number ... rank_t>
        requires(sizeof...(rank_t) == rank_v)
        multiptr(item_t const * ptr, rank_t const & ... length) :
            m_ptr{ (item_t *)ptr }, m_rank{ uxx(length)... }{
        }

        template<inc::is_number ... rank_t>
        requires(sizeof...(rank_t) == rank_v)
        multiptr(inc::seqptr<item_t> seq, rank_t const & ... length) :
            m_ptr{ (item_t *)seq }, m_rank{ uxx(length)... }{
        }

    private:
        multiptr(item_t const * ptr, uxx const * length_list) :
            m_ptr{ (item_t *)ptr }{
            
            for(uxx i = 0; i < rank_v; i++){
                m_rank[i]           = length_list[i];
            }
        }

        typename multiptr<item_t, rank_v - 1>::self_t random_get(uxx index) const {
            auto i_offset           = uxx{1};

            for(uxx i = 1; i < rank_v; i++){
                i_offset           *= m_rank[i];
            }

            auto subset             = multiptr<item_t, rank_v - 1>(m_ptr + i_offset * index, m_rank + 1);
            return subset.self();
        }

        self_t & self(){
            return *this;
        }
    $
}

namespace mixc::interface_multiptr::origin{
    using mixc::interface_multiptr::multiptr;
}

#endif

xexport_space(mixc::interface_multiptr::origin)